package config

import (
	"fmt"
	"sync"

	"github.com/spf13/viper"
)

// Config represents shared configuration schema loaded via Viper.
type Config struct {
	App struct {
		Name        string `mapstructure:"name"`
		Environment string `mapstructure:"environment"`
		LogLevel    string `mapstructure:"log_level"`
		HTTPPort    int    `mapstructure:"http_port"`
		GRPCPort    int    `mapstructure:"grpc_port"`
		JWTSecret   string `mapstructure:"jwt_secret"`
	} `mapstructure:"app"`

	Mongo struct {
		URI      string `mapstructure:"uri"`
		Database string `mapstructure:"database"`
	} `mapstructure:"mongo"`

	Redis struct {
		Addr     string `mapstructure:"addr"`
		Username string `mapstructure:"username"`
		Password string `mapstructure:"password"`
		DB       int    `mapstructure:"db"`
	} `mapstructure:"redis"`

	Prometheus struct {
		URL           string `mapstructure:"url"`
		Alertmanager  string `mapstructure:"alertmanager"`
		QueryTimeoutS int    `mapstructure:"query_timeout_seconds"`
	} `mapstructure:"prometheus"`

	AI struct {
		Provider   string `mapstructure:"provider"`
		OpenAIKey  string `mapstructure:"openai_api_key"`
		AnthropicKey string `mapstructure:"anthropic_api_key"`
		OllamaHost string `mapstructure:"ollama_host"`
	} `mapstructure:"ai"`

	Services struct {
		AlertService  string `mapstructure:"alert_service"`
		TicketService string `mapstructure:"ticket_service"`
		AIService     string `mapstructure:"ai_service"`
	} `mapstructure:"services"`
}

var (
	cfg  Config
	once sync.Once
)

// Load initializes Viper and unmarshals configuration into Config singleton.
func Load(configPaths ...string) (*Config, error) {
	var err error
	once.Do(func() {
		setupDefaults()

		v := viper.New()
		v.SetEnvPrefix("DSB")
		v.AutomaticEnv()
		v.SetConfigType("yaml")

		for _, path := range configPaths {
			v.SetConfigFile(path)
			if readErr := v.ReadInConfig(); readErr == nil {
				break
			}
		}

		if unmarshallErr := v.Unmarshal(&cfg); unmarshallErr != nil {
			err = fmt.Errorf("config: failed to unmarshal configuration: %w", unmarshallErr)
		}
	})

	if err != nil {
		return nil, err
	}

	return &cfg, nil
}

func setupDefaults() {
	viper.SetDefault("app.name", "devops-smartbot")
	viper.SetDefault("app.environment", "development")
	viper.SetDefault("app.log_level", "info")
	viper.SetDefault("app.http_port", 8080)
	viper.SetDefault("app.grpc_port", 9000)

	viper.SetDefault("prometheus.query_timeout_seconds", 30)
}

// MustLoad wraps Load and panics on error. Use in service main functions.
func MustLoad(configPaths ...string) *Config {
	cfg, err := Load(configPaths...)
	if err != nil {
		panic(err)
	}
	return cfg
}

// Get returns already loaded config or panics if Load not called.
func Get() *Config {
	if cfg.App.Name == "" {
		panic("config: must call Load before Get")
	}
	return &cfg
}
